/**
 * This module is used as a component for the WateringControlModule.
 * The module controls a stepper motor through the LKN sensor board. It implements opening and closing
 * the valve. Degree of valve open is controllable.
 * The stepper motor is used later to simulate a valve which pipeline system.
 *
 * @author Paweł Pawłowski <abdul-pablo@tlen.pl>
 * @author Leily Zafari
 */


#include "valve.h"

module ValveM{
	provides interface Valve;

	uses {
		interface SBoard;
		interface Timer<TMilli> as TimerMotor;
	}
}

implementation{

	uint8_t valveThrottle = 0; //current valve position
	uint8_t movement = 0; //steps to be done
	bool direction = FALSE; //false -> clockwise, true -> counter-clockwise
	bool open_or_close = TRUE; //true -> opening the valve, false -> closing the valve

	/**
	 * @brief Event triggered by firing of TimerMotor and implementing stepper-motor rotation.
	 * @details Timer used to control speed of valve rotation by means of timer period.
	 * Through the parameter "direction" the direction of the rotation of the stepper-motor is defined.
	 * The TimerMotor will be fired until the desired degree of rotation is achieved.
	 *
	 * @return void
	 **/
	event void TimerMotor.fired()
	{
		if(!direction)
		{
			call SBoard.stepCW();
			movement--;
			valveThrottle++;
		}
		else
		{
			call SBoard.stepCCW();
			movement--;
			valveThrottle--;
		}

		if(!movement)
		{
			call TimerMotor.stop();
			if(open_or_close)
				signal Valve.openDone(SUCCESS);
			else
				signal Valve.closeDone(SUCCESS);
		}
	}

	/**
	 * @brief This command opens the valve to specified position.
	 * @details Depending on the given value and the previous position of the stepper motor
	 * the value and the direction of the movement would be calculated and the periodic timer would be activated.
	 * These values would be used every time the timer is fired to move the stepper motor until the desired position is achieved.
	 *
	 * @see TimerMotor.fired()
	 *
	 * @param throttle uint8_t It defines how much the stepper motor should move.
	 * @return void
	 **/
	command void Valve.open(uint8_t throttle)
	{
		//open the valve
		open_or_close = TRUE;
		if(throttle > valveThrottle)
		{
			movement = throttle - valveThrottle;
			direction = FALSE;
			call TimerMotor.startPeriodic(TIMER_VALVE_MOTOR);
		}
		else if (throttle < valveThrottle)
		{
			direction = TRUE;
			movement = valveThrottle - throttle;
			call TimerMotor.startPeriodic(TIMER_VALVE_MOTOR);
		}
	}

	/**
	 * It opens valve to the full extent.
	 *
	 * @return void
	 */
	command void Valve.openFull(){
		call Valve.open(255);
	}

	/**
	 * @brief This command opens the valve to specified position.
	 * @details The number of motor-steps would be calculated
	 * depending on the position of the stepper motor. The periodic timer is activated.
	 *
	 * @see TimerMotor.fired()
	 *
	 * @return void
	 **/
	command void Valve.close()
	{
		if(valveThrottle)
		{
			movement = valveThrottle;
			direction = TRUE;
			open_or_close = FALSE;
			call TimerMotor.startPeriodic(TIMER_VALVE_MOTOR);
		}
		else
			signal Valve.closeDone(SUCCESS);
	}

	/**
	 * @brief It returns current position of the valve.
	 *
	 * @return uint8_t Current valve position
	 */
	command uint8_t Valve.getValvePosition(){
		return valveThrottle;
	}

	/**
	 * Event signaled after reading from A/D converter
	 *
	 * @param channel uint8_t Number of analog channel that was sampled by the A/D converter
	 * @param value uint8_t Value return by the ADC with respect to reference voltage
	 * @return void
	 */
	async event void SBoard.readDoneADC(uint8_t channel, double value){

	}

	/**
	 * Event signaled after reading from SBoard IO port
	 *
	 * @param value uint8_t Value of IO port return by SBoard component
	 * @return void
	 */
	async event void SBoard.readDoneIO(uint8_t value){

	}


}